#include "sqlconnpool.h"
#include <cassert>
#include <cstddef>
#include <mutex>
#include <mysql/mysql.h>
#include <semaphore.h>

using namespace std;

SqlConnPool::SqlConnPool() {
    useCount_ = 0;
    freeCount_ = 0; // 这个为什么是0？是因为还没有请求到SQL连接嘛
}

SqlConnPool* SqlConnPool::Instance() {
    static SqlConnPool connPool;
    return &connPool;
}

void SqlConnPool::Init(const char* host, int port,
                    const char* user, const char* pwd,
                    const char* dbName,
                    int connSize = 10) {
    assert(connSize > 0);

    for(int i=0; i<connSize; i++) {
        MYSQL* sql = nullptr;
        sql = mysql_init(sql);
        if(sql == nullptr) {
            LOG_ERROR("MYSQL init error!");
            assert(sql);
        }
        sql = mysql_real_connect(sql, host,
                                user, pwd,
                                dbName, port,
                                nullptr, 0);
        if(sql == nullptr) {
            LOG_ERROR("MYSQL connect error!");
        }
        connQue_.push(sql);
    }
    MAX_CONN_ = connSize;
    /*
        对于信号量的使用还是有很多的疑惑
    */
    sem_init(&semId_, 0, MAX_CONN_);
}

MYSQL* SqlConnPool::GetConn() {
    MYSQL* sql = nullptr;
    if(connQue_.empty()) {
        LOG_WARN("SqlConnPool busy!");
        return nullptr;
    }

    sem_wait(&semId_);
    {
        lock_guard<mutex> locker(mtx_);
        sql = connQue_.front();
        connQue_.pop();
    }
    assert(sql != nullptr);
    return sql;
}

void SqlConnPool::FreeConn(MYSQL *sql) {
    assert(sql != nullptr);
    lock_guard<mutex> locker(mtx_);
    connQue_.push(sql);
    sem_post(&semId_);
}

void SqlConnPool::ClosePool() {
    lock_guard<mutex> locker(mtx_);
    while(!connQue_.empty()) {
        auto item = connQue_.front();
        connQue_.pop();
        mysql_close(item);
    }
    mysql_library_end();
}

int SqlConnPool::GetFreeConnCount() {
    lock_guard<mutex> locker(mtx_);
    return connQue_.size();
}

SqlConnPool::~SqlConnPool() {
    ClosePool();
}